package com.bolt.admin.security.shiro.filter;


import com.bolt.admin.security.shiro.exception.AuthErrorException;
import com.bolt.admin.security.shiro.jwt.TokenProvider;
import com.bolt.admin.security.shiro.token.JWTToken;
import com.bolt.common.BoltConstants;
import com.bolt.common.utils.JacksonUtil;
import com.bolt.common.utils.SpringContextUtil;
import com.bolt.common.utils.StrUtil;
import com.bolt.common.web.ResponseUtil;
import com.bolt.convention.data.Results;
import com.bolt.convention.data.code.AuthCode;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created by Administrator on 2018/11/14.
 */
public class JWTFilter extends AccessControlFilter {

    private static final Logger logger = LoggerFactory.getLogger(JWTFilter.class);


    private String resolveToken(HttpServletRequest request) {
        TokenProvider tokenProvider = SpringContextUtil.getBean(TokenProvider.class);
        return tokenProvider.getToken(request);
    }

    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String accessToken = resolveToken(httpServletRequest);
        return new JWTToken(accessToken);
    }


    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) {
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        Subject subject = getSubject(servletRequest, servletResponse);
        // 判断是否为JWT认证请求
        try {
            if (isJwtSubmission(servletRequest)) {
                JWTToken token = (JWTToken) createToken(servletRequest, servletResponse);
                subject.login(token);
                return true;
            } else {
                // 请求未携带jwt 判断为无效请求
                ResponseUtil.renderJson(response,
                        JacksonUtil.toJSONString(Results.failure(AuthCode.MISSING_ACCESS_TOKEN)));
                return false;
            }
        } catch (Exception ex) {
            if(ex instanceof AuthErrorException){
                AuthErrorException authErrorException = (AuthErrorException)ex;
                ResponseUtil.renderJson(response,
                        JacksonUtil.toJSONString(Results.error(authErrorException.getCode(),authErrorException.getMessage())));
            }
            ResponseUtil.renderError(response, HttpStatus.UNAUTHORIZED.value(),
                    JacksonUtil.toJSONString(Results.error(AuthCode.INVALID_ACCESS_TOKEN, ex)));
            return false;
        }

    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        return true;
    }


    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        if (isAccessAllowed(request, response, mappedValue)) {
            return onAccessDenied(request, response, mappedValue);
        } else {
            return false;
        }
    }


    private boolean isJwtSubmission(ServletRequest request) {
        String jwt = ((HttpServletRequest) request).getHeader( BoltConstants.AUTH_HEADER);
        return (request instanceof HttpServletRequest) && StrUtil.isNotBlank(jwt);

    }


}
